package newxml.netconnect;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingVolume;
import com.jme.input.MouseInput;
import com.jme.scene.Spatial;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.export.Savable;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.export.binary.BinaryImporter;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ServerSocketFactory;
import javax.swing.UIManager;
import newxml.XMLImporter;

public class Server extends SimpleGame{
    private boolean running = true;
    
    private Class<BoundingVolume> bounds;
    private URL texturePath;
    private URL exportPath;
    
    private boolean clearSceneOnInput = true;
    
    public static void main(String[] args) {
        try{
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }catch(Exception e){/*nevermind*/}
        new Server().start();
    }
    
    @Override
    protected void simpleInitGame() {
        try {
            Properties prop = new Properties();
            prop.loadFromXML(new FileInputStream("config.xml"));
            setTexturePath(new URL(prop.getProperty("texturePath")));
            setExportPath(new URL(prop.getProperty("exportPath")));
        } catch (Exception ex) {
        }
        
        MouseInput.get().setCursorVisible(true);
        DisplaySystem.getDisplaySystem().setVSyncEnabled(true);
        org.lwjgl.opengl.Display.setLocation(0, 0);
        NetConnectControls ncc = new NetConnectControls(this);
        ncc.setLocation(properties.getWidth() + 10, 0);
        ncc.setVisible(true);
        openServer();
    }

    void loadScene(File selectedFile) throws Exception{
        Spatial spat = (Spatial) BinaryImporter.getInstance().load(selectedFile);
        rootNode.detachAllChildren();
        rootNode.attachChild(spat);
    }
    
    void sceneToBinary(File selectedFile) throws IOException{
        BinaryExporter.getInstance().save(rootNode, selectedFile);
        setExportPath(selectedFile.toURI().toURL());
    }
    
    private void openServer() {
        try {
            final ServerSocket srv = ServerSocketFactory.getDefault().createServerSocket();
            srv.bind(new InetSocketAddress(5678));
            ServerThread st = new ServerThread(srv);
            st.start();
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public Class<BoundingVolume> getBounds() {
        return bounds;
    }

    public void setBounds(Class<BoundingVolume> bounds) {
        this.bounds = bounds;
    }

    public URL getTexturePath() {
        return texturePath;
    }

    public void setTexturePath(URL texturePath) {
        this.texturePath = texturePath;
    }

    public boolean isClearSceneOnInput() {
        return clearSceneOnInput;
    }

    public void setClearSceneOnInput(boolean clearSceneOnInput) {
        this.clearSceneOnInput = clearSceneOnInput;
    }

    @Override
    public void finish() {
        super.finish();
        try {
            Properties prop = new Properties();
            prop.put("texturePath", getTexturePath().toExternalForm());
            prop.put("exportPath", getExportPath().toExternalForm());
            prop.storeToXML(new FileOutputStream("config.xml"), null);
        } catch (Exception ex) {
            Logger.getLogger(getClass().getName()).log(Level.WARNING, null, ex);
        }

    }

    public URL getExportPath() {
        return exportPath;
    }

    public void setExportPath(URL exportPath) {
        this.exportPath = exportPath;
    }

    private class ServerThread extends Thread {
        private final ServerSocket srv;
        public ServerThread(ServerSocket srv) {
            super("ServerThread");
            this.srv = srv;
        }
        
        @Override
        public void run() {
            while (running) {
                try {
                    Socket sock = srv.accept();
                    InputStream is = new BufferedInputStream(sock.getInputStream());
                    
                    SimpleResourceLocator resLoc = null;
                    if(getTexturePath() != null){
                        resLoc = new SimpleResourceLocator(getTexturePath());
                        ResourceLocatorTool.addResourceLocator(
                            ResourceLocatorTool.TYPE_TEXTURE, resLoc );
                    }
                    
                    final Savable sav = new XMLImporter().load(is);
                    
                    ResourceLocatorTool.removeResourceLocator(
                            ResourceLocatorTool.TYPE_TEXTURE, resLoc );
                    
                    Callable c = new Callable() {
                        public Object call() throws Exception {
                            if(sav instanceof Spatial){
                                Spatial spat = (Spatial) sav;
                                if(isClearSceneOnInput()){
                                    rootNode.detachAllChildren();
                                }
                                rootNode.attachChild((Spatial) sav);
                                if(getBounds() != null){
                                    spat.setModelBound(getBounds().newInstance());
                                    spat.updateModelBound();
                                }
                                rootNode.updateGeometricState(0, true);
                                rootNode.updateRenderState();
                            }
                            return null;
                        }
                    };
                    GameTaskQueueManager.getManager().update(c);
                    is.close();
                } catch (Exception ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}
